package com.pingan.haofang.searchcloud.indexdatasource.facade.impl;

import com.pingan.haofang.searchcloud.common.constants.Status;
import com.pingan.haofang.searchcloud.common.dto.OperationResult;
import com.pingan.haofang.searchcloud.common.exception.NotFoundException;
import com.pingan.haofang.searchcloud.index.dao.IndexDao;
import com.pingan.haofang.searchcloud.index.domain.Index;
import com.pingan.haofang.searchcloud.index.dto.IndexBuildProgressDTO;
import com.pingan.haofang.searchcloud.index.dto.IndexQueryResult;
import com.pingan.haofang.searchcloud.index.service.IndexService;
import com.pingan.haofang.searchcloud.indexdatasource.dao.IndexDatasourceDao;
import com.pingan.haofang.searchcloud.indexdatasource.domain.IndexDatasource;
import com.pingan.haofang.searchcloud.indexdatasource.dto.IndexDatasourceBuildDTO;
import com.pingan.haofang.searchcloud.indexdatasource.dto.IndexDatasourceDTO;
import com.pingan.haofang.searchcloud.indexdatasource.dto.IndexDatasourceScheduleImportDTO;
import com.pingan.haofang.searchcloud.indexdatasource.dto.ScheduleTaskDto;
import com.pingan.haofang.searchcloud.indexdatasource.facade.IndexDatasourceScheduleFacade;
import com.pingan.haofang.searchcloud.indexdatasource.service.IndexDatasourceScheduleService;
import com.pingan.haofang.searchcloud.indexdatasource.service.IndexDatasourceService;
import com.pingan.haofang.searchcloud.quartz.dto.TaskQueryDto;
import com.pingan.haofang.searchcloud.user.dao.SearchProjectDao;
import com.pingan.haofang.searchcloud.user.domain.SearchProject;
import com.pingan.haofang.searchcloud.user.dto.SearchProjectDto;
import com.pingan.haofang.searchcloud.user.service.SearchProjectService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * 索引构建调度Facade接口的实现
 *
 * @author baojie371
 * @date 17/5/18
 * @since 1.0.0
 */
@Service
public class IndexDatasourceScheduleFacadeImpl implements IndexDatasourceScheduleFacade {

    private static final Logger LOGGER = LoggerFactory.getLogger(IndexDatasourceScheduleFacadeImpl.class);

    //不配置定时设置时，默认cron表达式为了能注册任务
    @Value("${batch.default.cron:0 15 10 ? * 6L 2097-2099}")
    private String defaultCron;

    @Autowired
    private IndexDatasourceScheduleService indexDatasourceScheduleService;

    @Autowired
    private IndexDao indexDao;

    @Autowired
    private SearchProjectDao searchProjectDao;

    @Autowired
    private IndexDatasourceDao indexDatasourceDao;

    @Autowired
    private IndexDatasourceService indexDatasourceService;

    @Autowired
    private IndexService indexService;

    @Autowired
    private SearchProjectService searchProjectService;

    @Override
    public OperationResult importDatasource(long indexId, IndexDatasourceScheduleImportDTO dto) {

        Index index = Optional.ofNullable(indexDao.findOne(indexId))
                .orElseThrow(() -> new NotFoundException("Index Not Found"));
        if (!index.getStatus().equals(Status.NORMAL.getValue())) {
            return OperationResult.of(false, "Index status unnormal");
        }

        SearchProject searchProject = Optional.ofNullable(searchProjectDao.findOne(index.getProjectId()))
                .orElseThrow(() -> new NotFoundException("Project Not Found"));
        if (!searchProject.getStatus().equals(Status.NORMAL.getValue())) {
            return OperationResult.of(false, "Project status unnormal");
        }

        IndexDatasource indexDatasource = null;
        if (dto.getDatasourceId() != null) {
            indexDatasource = Optional.ofNullable(indexDatasourceDao.findOne(dto.getDatasourceId()))
                    .orElseThrow(() -> new NotFoundException("IndexDatasource Not Found"));
        }

        IndexBuildProgressDTO progressDTO = indexDatasourceScheduleService
                .updateProgress(dto, searchProject, index, indexDatasource);

        return indexDatasourceScheduleService.importDatasource(searchProject, index, indexDatasource, progressDTO);
    }

    @Override
    public List<ScheduleTaskDto> getAllEffectiveTasks(TaskQueryDto dto) {
        // 获取所有的索引
        List<IndexQueryResult> indexQueryResult = indexService.queryAllIndexOfStorage(dto);
        if (CollectionUtils.isEmpty(indexQueryResult)) {
            return Collections.emptyList();
        }

        // <indexId -> Index>
        Map<Long, IndexQueryResult> indexQueryResultMap = indexQueryResult.stream()
                .collect(Collectors.toMap(IndexQueryResult::getId, (p) -> p));


        // 查询所有项目
        List<SearchProjectDto> projectDtos = searchProjectService.findEnableProjects();

        // <projectId -> project>
        Map<Long, SearchProjectDto> projectDtoMap = projectDtos.stream()
                .collect(Collectors.toMap(SearchProjectDto::getId, (p) -> p));

        List<IndexDatasourceDTO> indexDatasourceDTOList =
                indexDatasourceService.findDatasourceByIndexIds(indexQueryResultMap.keySet());
        // <indexId -> datasourceList>
        Map<Long, List<IndexDatasourceDTO>> indexDatasourceDTOMap = indexDatasourceDTOList.stream().collect(
                Collectors.groupingBy(indexDatasourceDTO -> indexDatasourceDTO.getIndexId())
        );

        List<IndexDatasourceBuildDTO> indexDatasourceBuildDTOList = indexDatasourceService.
                findDatasourceBuildByIndexIds(indexQueryResultMap.keySet());
        Map<Long, IndexDatasourceBuildDTO> indexDatasourceBuildDTOMap = indexDatasourceBuildDTOList.stream()
                .collect(Collectors.toMap(IndexDatasourceBuildDTO::getIndexId, (p) -> p));


        List<ScheduleTaskDto> result = new ArrayList<>();
        // 拼接
        for (Map.Entry<Long, List<IndexDatasourceDTO>> entry : indexDatasourceDTOMap.entrySet()) {
            IndexQueryResult index = indexQueryResultMap.get(entry.getKey());

            if (!projectDtoMap.containsKey(index.getProjectId())) {
                LOGGER.debug("project {} is not enable", index.getProjectId());
                continue;
            }

            SearchProjectDto projectDto = projectDtoMap.get(index.getProjectId());
            ScheduleTaskDto scheduleTaskDto = new ScheduleTaskDto();
            scheduleTaskDto.setProjectCode(projectDto.getProjectCode());
            scheduleTaskDto.setIndexName(index.getIndexName());
            scheduleTaskDto.setIndexId(index.getId());
            scheduleTaskDto.setIndexDatasourceDTOs(entry.getValue());
            scheduleTaskDto.setCron( Optional.ofNullable(indexDatasourceBuildDTOMap.get(index.getId()))
                    .map(IndexDatasourceBuildDTO::getCron).orElse(defaultCron));
            scheduleTaskDto.setIncCron(Optional.ofNullable(indexDatasourceBuildDTOMap.get(index.getId()))
                    .map(IndexDatasourceBuildDTO::getIncCron).orElse(null));

            result.add(scheduleTaskDto);
        }
        return result;
    }
}
